<?php
/**
-------------------------
GNU GPL COPYRIGHT NOTICES
-------------------------
This file is part of FlexicaCMS.

FlexicaCMS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

FlexicaCMS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with FlexicaCMS.  If not, see <http://www.gnu.org/licenses/>.*/

/**
 * $Id$
 *
 * @author FlexicaCMS team <contact@flexicacms.com>
 * @link http://www.flexicacms.com/
 * @copyright Copyright &copy; 2009-2010 Gia Han Online Solutions Ltd.
 * @license http://www.flexicacms.com/license.html
 */
class DynamicForm extends FWidget
{
    /**
    * @var array form data
    */
    public $attributes;
    /**
    * @var array configuration for each field to render its input element
    */
    public $config;
    
    public $elements = array();
    
    protected $groups = array();
    
    public function init() {
        parent::init();
        
        // prepare the list of input elements
        foreach($this->attributes as $fieldName => $attr) {
            //remove suffix if field is one of multi values fields
            if (($pos = strpos($fieldName,' ')) !== false)
            {
                list($group,$fieldName,$i) = explode(' ',$fieldName);
                $conf = $this->config[$group][$fieldName];
                $attr->name .='[]';
                // count number of field in the group & save this info for rendering fieldset
                if (!isset($this->groups[$group]))
                    $this->groups[$group] = count($this->config[$group]);
            }    
            else
            {
                $group = '';
                $conf = $this->config[$fieldName];
            }

            $elm = new FormElement($attr);
            if (!empty($group))
                $elm->group = $group;
            if (isset($conf['type']))
                $elm->type = $conf['type'];
            if (isset($conf['rules']))
                $elm->param->rules = $conf['rules'];
            if (isset($conf['items']))
                $elm->items = $conf['items'];
            if (isset($conf['htmlOptions']))
                $elm->htmlOptions = $conf['htmlOptions'];
            $this->elements[] = $elm;
        }

        // save new values
//        if (Yii::app()->request->IsPostRequest){
//            foreach($this->params as &$param) {
//                if (!isset($_POST[$param->name])) continue;
//                
//                $param->value = $_POST[$param->name];
//                if (! $param->save()) {
//                    FErrorHandler::logError($param->getError('value'));
//                }
//            }
            //update Settings Class
//            if (isset($_POST['SettingParam'], $_POST['SettingParam']['module'])) {
//                $modules = $_POST['SettingParam']['module'];
//                if (empty($modules)) {
                    //render all
//                    Yii::import('Core.models.SettingParam');
//                    $modules = SettingParam::model()->getModules();
                    //remove 'System' module
//                    if (count($modules))
//                        array_pop($modules);
//                } elseif ($modules == 'system_module') {
                    //update module system
//                    $modules = array('');
//                } else
//                    $modules = array($modules);
//                foreach ($modules as $module)
//                    FSM::run('Core.Settings.db2php', array('module' => $module));
//            }
//        }
        
    }
    
    /**
    * Render field's input element
    * 
    * @param string $name field name
    */
    public function renderField($name){
        echo $this->elements[$name]->render();
    }
    
    public function beginForm() {
        echo "<div class=\"form wide\">\n";
        echo CHtml::beginForm('', 'post');
    }
    
    public function endForm() {
        echo '<div class="row">',CHtml::submitButton('Save',array('class' => 'buttons')),'</div>';
        echo "</form>\n</div>";
    }
    
    /**
    * render parameter form. Customized render script can use 
    * renderParam(), beginForm(), endForm() to show the form 
    */
    public function render(){
        $this->beginForm();
        
        $groupPos = 0;
        foreach($this->elements as $name => $elm)
        {
            if (!empty($elm->group)) 
                $groupPos++;

            if ($groupPos == 1)
                echo "<fieldset class=\"widget-group fieldset_{$elm->group}\"><div class=\"item-overlay\"><div class=\"overlay-bg\"></div><div class=\"drag-handle\"><div></div></div></div><div class=\"item-content\">";

            $this->renderField($name);

            if (!empty($elm->group) && $groupPos >= $this->groups[$elm->group])
            {
                echo '<label>&nbsp;</label>', //for the padding
                     '<a class="add" href="#" onclick="return duplicate(this)" title="Add">Add</a>',
                     '<a class="remove" href="#" onclick="return remove(this)" title="Remove">Remove</a>',
                     '<a class="up" href="#" title="Move Up">Move Up</a>',
                     '<a class="down" href="#" title="Move Down">Move Down</a>',
                     '</div></fieldset>';
                $groupPos = 0;
                $options = array(
                    'items'=>'fieldset',
                    'handle'=>'.drag-handle',
                );
                $options=CJavaScript::encode($options);
                Yii::app()->getClientScript()->registerScript(__CLASS__.'#Sortable',"jQuery('form').sortable({$options});");
                $cs=Yii::app()->getClientScript();
                $scriptUrl=$cs->getCoreScriptUrl().'/jui/js';
                $themeUrl=$cs->getCoreScriptUrl().'/jui/css';
                $cs->registerCssFile($themeUrl.'/base/jquery-ui.css');

                $cs->registerCoreScript('jquery');
                $script = "
jQuery('body').delegate('.widget-group .item-content', 'mouseover', function(){
    jQuery('.widget-group .item-overlay').hide();
    var width = jQuery(this).width();
    var height = jQuery(this).height();
    jQuery(this)
        .siblings('.item-overlay')
            .width(50)
            .height(height)
            .show();
});
jQuery('body').delegate('.widget-group .item-content .up', 'click', function(){
    var current_item = jQuery(this).closest('.widget-group');
    var prev_item = current_item.prev();
    if (prev_item.size())
        prev_item.before(current_item);
    return false;
});
jQuery('body').delegate('.widget-group .item-content .down', 'click', function(){
    var current_item = jQuery(this).closest('.widget-group');
    var next_item = current_item.next();
    if (next_item.size())
        next_item.after(current_item);
    return false;
});
                ";
                $cs->registerScript(__CLASS__.'#SortItem', $script);
                $cs->registerScriptFile($scriptUrl.'/jquery-ui.min.js');
            }
        }    
        $this->endForm();
    }
    
}

class FormElement extends CComponent {
    /**
     * @var array Core input types (alias=>CHtml method name)
     */
    public static $coreTypes=array(
        'text'=>'textField',
        'hidden'=>'hiddenField',
        'password'=>'passwordField',
        'textarea'=>'textArea',
//        'file'=>'fileField',
        'radio'=>'radioButton',
        'checkbox'=>'checkBox',
        'listbox'=>'listBox',
        'dropdownlist'=>'dropDownList',
        'checkboxlist'=>'checkBoxList',
        'radiolist'=>'radioButtonList',
    );

    public $param;
    
    public $group='';
    
    public $type='text';
    
    public $items=array();
    
    public $htmlOptions=array();
    
    protected $layout="<div class=\"row\">\n{label}\n{input}\n{hint}\n{error}\n</div>";
    
    /**
    * @param SettingParam $param
    * @return ParamFormElement
    */
    public function __construct($param) {
        $this->param = $param;
    }
    
    public function render()
    {
        if ($this->type != 'hidden')
        {
            $output=array(
                '{label}'=>$this->renderLabel(),
                '{input}'=>$this->renderInput(),
                '{hint}'=>$this->renderHint(),
                '{error}'=>'' //$this->getParent()->showErrorSummary ? '' : $this->renderError(),
            );
            return strtr($this->layout,$output);
        } else
            return $this->renderInput();
    }
    
    /**
     * Renders the label for this input.
     * The default implementation returns the result of {@link CHtml activeLabelEx}.
     * @return string the rendering result
     */
    public function renderLabel()
    {
        //remove path to external widget
        preg_match('/WidgetData\[([^\]]+)\]/i', $this->param->name, $matches);
        if (count($matches) > 1)
        {
            list($label,) = explode('_', $matches[1], 2);
            if (strpos($label, '.'))
            {
                $label = ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $label)))));
                $label = str_replace($label, '', $this->param->label);
                if (strlen($label))
                {
                    $this->param->label = preg_replace('/\s+/', ' ', $label);
                }
            }
        }
        return CHtml::label($this->param->label, $this->param->name);
    }

    /**
     * Renders the input field.
     * The default implementation returns the result of the appropriate CHtml method or the widget.
     * @return string the rendering result
     */
    public function renderInput()
    {
        if (in_array($this->type, array('link'))) $this->type = 'text';
        if(isset(self::$coreTypes[$this->type]))
        {
            if (!is_array($this->htmlOptions)) $this->htmlOptions = array();
            if ($this->type == 'text')
                $this->htmlOptions = CMap::mergeArray(array('size'=>50), $this->htmlOptions);
            if ($this->type == 'textarea')
                $this->htmlOptions = CMap::mergeArray(array('cols'=>100,'rows'=>'10'), $this->htmlOptions);
            $method=self::$coreTypes[$this->type];
            if(strpos($method,'List')!==false)
                return CHtml::$method($this->param->name, $this->param->value, $this->items, $this->htmlOptions);
            else
                return CHtml::$method($this->param->name, $this->param->value, $this->htmlOptions);
        }
        else
        {
            if (strpos($this->type, '.') === false) {
                Yii::import('Admin.components.*');
                $this->type = ucfirst($this->type).'Widget';
            }
            $properties = array(
                'name'=>$this->param->name,
                'value'=>$this->param->value,
                'htmlOptions'=>$this->htmlOptions,
            );
            ob_start();
            Yii::app()->controller->widget($this->type, $properties);
            return ob_get_clean();
        }
    }

    /**
     * Renders the error display of this input.
     * The default implementation returns the result of {@link CHtml::error}
     * @return string the rendering result
     */
    public function renderError()
    {
    }

    /**
     * Renders the hint text for this input.
     * The default implementation returns the {@link hint} property enclosed in a paragraph HTML tag.
     * @return string the rendering result.
     */
    public function renderHint()
    {          
        return $this->param->description==''? '' : '<div class="hint">'.$this->param->description.'</div>';
    }
}

class DynamicFormAttribute extends CModel
{
    public $name;
    public $value;
    public $label;
    public $description;
    
    public function attributeNames(){
        return array('name','value','label','description');
    }
}
?>